package com.example.ioc.context;

import com.example.common.utils.Statistics;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.Scope;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 用Component无法注册Scope
 * 也可以通过 {@link org.springframework.beans.factory.config.CustomScopeConfigurer#addScope(String, Scope)}
 * 本质也是 {@link org.springframework.beans.factory.config.CustomScopeConfigurer#postProcessBeanFactory(ConfigurableListableBeanFactory)}
 * 或者
 * 需要用{@link org.springframework.beans.factory.config.ConfigurableBeanFactory#registerScope(String, Scope)}
 * 最好在{@link org.springframework.beans.factory.config.BeanFactoryPostProcessor#postProcessBeanFactory(ConfigurableListableBeanFactory)}
 * 中的前者中注册
 */
@Slf4j
public final class LScope implements Scope {

    public static final String SCOPE_NAME = "lScope";

    private static volatile LScope instance;

    private final Map<String, Object> contextMap = new ConcurrentHashMap<>();

    private final Map<String, Runnable> destructionCallbacks = new ConcurrentHashMap<>();

    private LScope() {
        Statistics.logInfo(log);
    }

    public static LScope getInstance() {
        if (instance == null) {
            synchronized (LScope.class) {
                if (instance == null) {
                    instance = new LScope();
                }
            }
        }
        return instance;
    }

    @NonNull
    @Override
    public Object get(@NonNull String name, @NonNull ObjectFactory<?> objectFactory) {
        Statistics.logInfo(log, "get", name);
        Object object = contextMap.get(name);
        if (object == null) {
            object = objectFactory.getObject();
            contextMap.put(name, object);
        }
        return object;
    }

    /**
     * 该方法在创建Bean的时候被调用
     * <p>
     * 该方法在
     * {@link org.springframework.beans.factory.support.AbstractBeanFactory#registerDisposableBeanIfNecessary(String, Object, RootBeanDefinition)}
     * 中被调用
     * <p>
     * 在作用域失效的时候才销毁bean,而不要立即销毁
     * 这个Runnable一般是{@link org.springframework.beans.factory.support.DisposableBeanAdapter}
     */
    @Override
    public void registerDestructionCallback(@Nullable String name, @NonNull Runnable callback) {
        Statistics.logInfo(log, "registerDestructionCallback", name);
        if (contextMap.containsKey(name)) {
            destructionCallbacks.put(name, callback);
        }
    }

    @Override
    public Object remove(@Nullable String name) {
        Statistics.logInfo(log, "remove", name);
        Runnable runnable = destructionCallbacks.remove(name);
        if (runnable != null) {
            runnable.run();
        }
        return contextMap.remove(name);
    }

    @Override
    public Object resolveContextualObject(@Nullable String key) {
        Statistics.logInfo(log, "resolveContextualObject", key);
        return null;
    }

    @Override
    public String getConversationId() {
        Statistics.logInfo(log, "getConversationId", "");
        return "";
    }
}
